grammar Sidl;

     
options {
    backtrack=true;
    memoize=true;
}
@parser::header {package sidl;}   
@lexer::header {package sidl;}   
@members {
	public Doc doc = new Doc();
	private Inf currentInf = null;
}                 
compilationUnit 
	:	
	(packageDeclaration )?      
	(importDeclaration)*
	(optionDeclaration)*
	 interfaceDeclaration
	 (clazzOrInterfaceDeclaration)*
	;	 
	 	
	 	

IDT  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

	
INT :	'0'..'9'+
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

CHAR:  '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
    ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

	
	
	



 packageDeclaration :	
 	'package' (packageNameDeclaration ) ';'       {doc.packageName = $packageNameDeclaration.text;}
	;	
	
	
packageNameDeclaration
	:	
	IDT (.IDT)*	
	;		
	
	
importDeclaration  :   
	'import'         IDT '.' '*' ';'       
	|   'import' 
        IDT  ('.' IDT)+   ('.' '*')?   ';'
    ;
    
    
clazzOrInterfaceDeclaration
    	:	
    	clazzDeclaration
    	|interfaceDeclaration;

    	

clazzDeclaration
	    : 'class' IDT            
	    {
	    doc.clazzes.addLast(new Clazz());
	    doc.clazzes.getLast().name = $IDT.text; 
	    }
        clazzBody
    ;


	
clazzBody 
    :   '{' 
        (clazzBodyDeclaration
        )* 
        '}'
    ;


clazzBodyDeclaration 
    :   ';'
    |   memberDecl
    ;

memberDecl 
    :    fieldDeclaration
    ;

fieldDeclaration 
    :   
        type IDT ';'  {doc.clazzes.getLast().fields.add(new Field(new Type($type.text), $IDT.text));} 
    ;
         
interfaceDeclaration 
    :   'interface' IDT 
                             {
                               currentInf = new Inf();
                               doc.infs.addLast(currentInf);
                               currentInf.name = $IDT.text;
                              }
        interfaceBody 
    ;
        

interfaceBody 
    :   '{' 
        (interfaceBodyDeclaration
        )* 
        '}'
    ;
    
interfaceBodyDeclaration 
    :
    interfaceConstDeclaration
    | interfaceMethodDeclaration
    |   ';'
    ;
      
interfaceConstDeclaration
	:	'const' IDT '=' number ';' {currentInf.consts.add(new Const($IDT.text, $number.text));}
	
	;

number	:	
INT
	|	 HEXINT
;

HEXINT	:	'0x'(HEX_DIGIT)+;

	
interfaceMethodDeclaration 
    :   {currentInf.funcs.add(new Func());}
        (type {currentInf.funcs.getLast().rtype = new Type($type.text);}
        |'void'{currentInf.funcs.getLast().rtype = new Type("void");}
        )
        IDT {currentInf.funcs.getLast().name = $IDT.text;} 
        formalParameters 
        ';'
    ;

    
formalParameters 
    :  '('
    (formalParameterDecls)?
     ')'
    ;

formalParameterDecls 
    :   normalParameterDecl
        (',' normalParameterDecl)*
    ;

normalParameterDecl 
    :   ('out')? type IDT  { currentInf.funcs.getLast().params.addLast(new Param(new Type($type.text),$IDT.text));}
    ;
    

type 
    :   IDT ('[' ']' )?
    ;

optionDeclaration
	:	
	'@options'  '{' 
	(optionAttribute)*
	'}'
	;
	
optionAttribute
	:	
	optionAttributeName '=' optionAttributeValue ';' {doc.options.put($optionAttributeName.text,$optionAttributeValue.text);}
	;

optionAttributeName:IDT;

optionAttributeValue:IDT;
		